home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / Palm Finder 2 / Src / Panes / menu.cpp < prev    next >
Encoding:
Text File  |  2001-06-23  |  8.5 KB  |  471 lines

  1. // menu.cpp
  2.  
  3. #include "menu.h"
  4. #include "menu_item.h"
  5.  
  6. #include "drawing.h"
  7. #include "events.h"
  8. #include "Finder_res.h"
  9.  
  10. // constants
  11. const unsigned short     left_margin = 3;
  12. const unsigned short     right_margin = 3;
  13. const int                    divider_height = 5;
  14. const int                    shortcut_width = 16;
  15. const int                    shortcut_icon_width = 9;
  16.  
  17. //
  18. // constructor
  19. //
  20. menu::menu( char* in_title, int in_bitmap_id, int x, int y, int baseline, int height, view* in_superview ):
  21.     pane(in_superview)
  22. {
  23.     // variables
  24.     int unused, width;
  25.     unsigned short length;
  26.     
  27.     // store member varibles
  28.     if (in_title==NULL) {
  29.         m_title[0] = 0;
  30.     } else {
  31.         StrCopy( m_title, in_title );
  32.     }
  33.     m_bitmap = in_bitmap_id;
  34.     m_baseline = baseline;
  35.     m_selected = false;
  36.     m_open = false;
  37.     m_saved_bits = NULL;
  38.     m_items = NULL;
  39.     m_selected_item = 0;
  40.     
  41.     length = StrLen(m_title);
  42.     if (length==0) {
  43.         get_bitmap_dimensions(in_bitmap_id, unused, width);
  44.         // add margins
  45.         width += left_margin + right_margin;
  46.     } else {
  47.         width = left_margin + FntCharsWidth(m_title, length) + right_margin;
  48.     }
  49.     
  50.     // determine dimensions
  51.     m_bounds.topLeft.x = x;
  52.     m_bounds.topLeft.y = y;
  53.     m_bounds.extent.x = short(width);
  54.     m_bounds.extent.y = height;
  55. }
  56.  
  57. //
  58. // destructor
  59. //
  60. menu::~menu(){
  61.     while (m_items!=NULL)
  62.         delete m_items;
  63. }
  64.  
  65. //
  66. // add_item()
  67. //
  68. void        
  69. menu::add_item (char* in_item, long in_id, char in_shortcut) {
  70.     new menu_item (in_item, in_id, in_shortcut, &m_items);
  71. }
  72.  
  73.  
  74. //
  75. // draw_self()
  76. //
  77. void
  78. menu::draw_self() {
  79.     // variables
  80.     int x = m_bounds.topLeft.x + int(left_margin);
  81.     int y = m_bounds.topLeft.y + m_baseline;
  82.     int length = int(StrLen(m_title));
  83.     
  84.     if (length==0) {
  85.         draw_bitmap (m_bitmap, x, y, left_align, bottom_align);
  86.     } else {
  87.         draw_string (m_title, x, y, left_align, baseline_align);
  88.     }
  89.     m_selected = false;
  90. }
  91.  
  92. //
  93. // click_self()
  94. //
  95. Boolean
  96. menu::click_self(int x, int y) {
  97.     #pragma unused (x, y)
  98.     
  99.     // return false so menu bar can handle click
  100.     return false;
  101. }
  102.  
  103. //
  104. // still_down_self()
  105. //
  106. Boolean
  107. menu::still_down_self(int x, int y) {
  108.     int menu_bar_top = m_bounds.topLeft.y;
  109.     int menu_bar_bottom = menu_bar_top + m_bounds.extent.y;
  110.     
  111.     // draw menu here in order to delay opening by one iteration,
  112.     // in order to alllow restore_bits to go to all menus first.
  113.     if (m_selected and not m_open) {
  114.         save_bits();
  115.         draw_menu();
  116.         m_open = true;
  117.         m_selected_item = 0;
  118.     }
  119.     
  120.     if ((menu_bar_top<=y) && (y<menu_bar_bottom)) {
  121.         if ( RctPtInRectangle(x, y, &m_bounds) != m_selected ) {
  122.             WinInvertRectangle (&m_bounds, 0);
  123.             m_selected = not m_selected;
  124.  
  125.             if (not m_selected) {
  126.                 // close menu
  127.                 restore_bits();
  128.                 m_open = false;
  129.                 m_selected_item = 0;
  130.             }
  131.         }
  132.     } else if (m_open) {
  133.         // track pen through open menu
  134.         int                 index = get_item_hit (x, y);
  135.         select_menu_item (index);
  136.     }
  137.  
  138.     return false;
  139. }
  140.  
  141. //
  142. // pen_up_self()
  143. //
  144. Boolean
  145. menu::pen_up_self(int x, int y) {
  146.     #pragma unused (x, y)
  147.     menu_item*    item = NULL;
  148.     int                 index;
  149.     int                id = 0;
  150.     
  151.     // if this menu is open, see if any selection was made
  152.     if (m_open) {
  153.         index = get_item_hit (x, y);
  154.         if (index!=0) {
  155.             item = get_item(index);
  156.             if (item!=NULL) {
  157.                 id = item->get_id();
  158.             }
  159.         }
  160.     }
  161.     
  162.     // un-invert title if inverted
  163.     if (m_selected) {
  164.         WinInvertRectangle (&m_bounds, 0);
  165.         restore_bits();
  166.         m_selected = false;
  167.         m_open = false;
  168.     }
  169.     
  170.     // send command down the chain of command
  171.     if (id!=0) {
  172.         send_menu_event (id, false, x, y);
  173.     }
  174.     
  175.     return false;
  176. }
  177.  
  178. #pragma mark -
  179.  
  180. //
  181. // get_menu_dimensions()
  182. //
  183. void                    
  184. menu::get_menu_dimensions( int& height, int& width ) {
  185.     menu_item*        item = m_items;
  186.     int                    linespace = FntLineHeight();
  187.     int                    linewidth;
  188.     unsigned short    length;
  189.     char                    s[64];
  190.     
  191.     height = 0;
  192.     width = 0;
  193.     while (item!=NULL) {
  194.         item->get_text(s);
  195.         if (StrCompare(s, "-")==0) {
  196.             height += divider_height;
  197.         } else {
  198.             height += linespace;
  199.             length = StrLen(s);
  200.             linewidth = FntCharsWidth(s, length) + left_margin + right_margin;
  201.             if (item->get_shortcut() != 0)
  202.                 linewidth += shortcut_width;
  203.             if (linewidth > width)
  204.                 width = linewidth;
  205.         }
  206.         item = (menu_item*) (item->get_next());
  207.     }
  208. }
  209.  
  210. //
  211. // get_menu_content_rect()
  212. //
  213. void                    
  214. menu::get_menu_content_rect( RectangleType* r ) {
  215.     int                    height, width;
  216.  
  217.     get_menu_dimensions (height, width);
  218.     r->topLeft.x = m_bounds.topLeft.x + 1;
  219.     r->topLeft.y = m_bounds.topLeft.y + m_bounds.extent.y + 1;
  220.     r->extent.x = width;
  221.     r->extent.y = height;
  222. }
  223.  
  224. //
  225. // get_menu_frame_rect()
  226. //
  227. void                    
  228. menu::get_menu_frame_rect( RectangleType* r ) {
  229.     get_menu_content_rect (r);
  230.     r->topLeft.x--;
  231.     r->topLeft.y--;
  232.     r->extent.x += 3;
  233.     r->extent.y += 3;
  234. }
  235.  
  236. //
  237. // draw_menu()
  238. //
  239. void                    
  240. menu::draw_menu( ) {
  241.     RectangleType        r;
  242.     PointType            s, e;
  243.     
  244.     get_menu_content_rect(&r);
  245.     
  246.     // check if rectangle is big enough
  247.     if ((r.extent.x<=2) || (r.extent.y<=2))
  248.         return;
  249.     
  250.     // draw bottom shadow
  251.     s.x = r.topLeft.x + 1;
  252.     s.y = r.topLeft.y + r.extent.y + 1;
  253.     e.x = r.topLeft.x + r.extent.x + 1;
  254.     e.y = s.y;
  255.     WinDrawLine(s.x, s.y, e.x, e.y);
  256.     
  257.     // draw right shadow
  258.     s.x = e.x;
  259.     s.y = r.topLeft.y + 2;
  260.     WinDrawLine(s.x, s.y, e.x, e.y);
  261.     
  262.     // draw rectangle frame
  263.     WinDrawRectangleFrame (simpleFrame, &r);
  264.     
  265.     // erase contents
  266.     WinEraseRectangle(&r, 0);
  267.     
  268.     // draw text
  269.     draw_menu_items();
  270. }
  271.  
  272. //
  273. // draw_menu_items()
  274. //
  275. void                    
  276. menu::draw_menu_items( ) {
  277.     menu_item*        item = m_items;
  278.     int                    linespace = FntLineHeight();
  279.     int                    shortcut_x, shortcut_letter_x;
  280.     int                    x, y;
  281.     int                    height, width, baseline;
  282.     char                    s[64];
  283.     char                    shortcut_letter;
  284.     
  285.     x = m_bounds.topLeft.x + 1;
  286.     y = m_bounds.topLeft.y + m_bounds.extent.y + 1;
  287.     get_menu_dimensions(height, width);
  288.     shortcut_x = x + width - shortcut_width - right_margin;
  289.     shortcut_letter_x = shortcut_x + shortcut_icon_width;
  290.     baseline = FntBaseLine();
  291.     
  292.     while (item!=NULL) {
  293.         item->get_text(s);
  294.         if (StrCompare(s, "-")==0) {
  295.             WinDrawGrayLine( x, y+divider_height/2, x+width-1,  y+divider_height/2);
  296.             y += divider_height;
  297.         } else {
  298.             draw_string(s, x+left_margin, y, left_align, top_align);
  299.             shortcut_letter = item->get_shortcut();
  300.             if (shortcut_letter!=0) {
  301.                 draw_bitmap(ShortcutBitmap, shortcut_x, y+baseline, left_align, bottom_align);
  302.                 draw_char(shortcut_letter, shortcut_letter_x, y, left_align, top_align);
  303.             }
  304.             y += linespace;
  305.         }
  306.         item = (menu_item*) (item->get_next());
  307.     }
  308. }
  309.  
  310. //
  311. // select_menu_item()
  312. //
  313. void                    
  314. menu::select_menu_item( int item ) {
  315.     if (m_selected_item==item) return;
  316.     
  317.     if (m_selected_item!=0)
  318.         invert_menu_item(m_selected_item);
  319.     if (item != 0)
  320.         invert_menu_item(item);
  321.  
  322.     m_selected_item = item;
  323. }
  324.  
  325. //
  326. // invert_menu_item()
  327. //
  328. void                    
  329. menu::invert_menu_item( int item ) {
  330.     RectangleType r;
  331.     
  332.     get_item_rect( item, &r );
  333.     WinInvertRectangle( &r, 0 );
  334. }
  335.  
  336. //
  337. // get_item_hit()
  338. //
  339. int                    
  340. menu::get_item_hit( int x, int y ) {
  341.     int                 max = count_items();
  342.     int                 i;
  343.     RectangleType r;
  344.     menu_item*    item = NULL;
  345.     
  346.     for (i=1; i<=max; i++) {
  347.         get_item_rect(i, &r);
  348.         if (RctPtInRectangle ( x, y, &r )) {
  349.             item = get_item(i);
  350.             if (item!=NULL)
  351.                 if (item->get_enabled()==true) {
  352.                     return i;
  353.                 } else {
  354.                     return 0;
  355.                 }
  356.         }
  357.     }
  358.     return 0;
  359. }
  360.  
  361. //
  362. // get_item_rect()
  363. //
  364. void                    
  365. menu::get_item_rect( int index, RectangleType* r ) {
  366.     menu_item*        item = m_items;
  367.     char                    s[64];
  368.     int                    i=1;
  369.     int                    linespace = FntLineHeight();
  370.     int                    y, height;
  371.     
  372.     get_menu_content_rect(r);
  373.     y = r->topLeft.y;
  374.     
  375.     while (item!=NULL) {
  376.         item->get_text(s);
  377.         if (StrCompare(s, "-")==0) {
  378.             height = divider_height;
  379.         } else {
  380.             height = linespace;
  381.         }
  382.         r->extent.y = height;
  383.         if (i==index) {
  384.             // item found, return its rect
  385.             r->topLeft.y = y;
  386.             r->extent.y = height;
  387.             return;
  388.         }
  389.         y += height;    
  390.         i++;
  391.         item = (menu_item*) (item->get_next());
  392.     }
  393.     
  394.     // item not found, return empty rect
  395.     r->topLeft.x = 0;
  396.     r->topLeft.y = 0;
  397.     r->extent.x = 0;
  398.     r->extent.y = 0;
  399.     return;
  400. }
  401.  
  402. //
  403. // count_items()
  404. //
  405. int
  406. menu::count_items() {
  407.     menu_item*        item = m_items;
  408.     int i=0;
  409.  
  410.     while (item!=NULL) {
  411.         i++;
  412.         item = (menu_item*) (item->get_next());
  413.     }
  414.     
  415.     return i;
  416. }
  417.  
  418. //
  419. // get_item()
  420. //
  421. menu_item*
  422. menu::get_item(int index) {
  423.     menu_item*        item = m_items;
  424.     int i=0;
  425.  
  426.     while (item!=NULL) {
  427.         i++;
  428.         if (i==index)
  429.             break;
  430.         item = (menu_item*) (item->get_next());
  431.     }
  432.     
  433.     return item;
  434. }
  435.  
  436. #pragma mark -
  437.  
  438. //
  439. // save_bits()
  440. //
  441. void                    
  442. menu::save_bits( ) {
  443.     // variables
  444.     unsigned short    err;
  445.     RectangleType     r;
  446.  
  447.     // calculate rectangle
  448.     get_menu_frame_rect (&r);
  449.     // dispose of any previously saved bits
  450.     if (m_saved_bits!=NULL) {
  451.         restore_bits();
  452.     }
  453.     // save rectangle
  454.     m_saved_bits = WinSaveBits (&r, &err);
  455. }
  456.  
  457. //
  458. // restore_bits()
  459. //
  460. void                    
  461. menu::restore_bits( ) {
  462.     RectangleType     r;
  463.  
  464.     // calculate rectangle
  465.     get_menu_frame_rect (&r);
  466.     // restore bits
  467.     if (m_saved_bits!=NULL)
  468.         WinRestoreBits (m_saved_bits, r.topLeft.x, r.topLeft.y);
  469.     m_saved_bits = NULL;
  470. }
  471.